package com.gitee.lp.convert;

import com.gitee.lp.AppManager;
import com.gitee.lp.dm.DmMapper;
import com.gitee.lp.oracle.OracleMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import oracle.sql.BLOB;
import org.apache.commons.io.IOUtils;
import org.apache.ibatis.session.*;


import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


public class ConvertTabel implements Runnable {


    SqlSessionFactory oracleSessionFactory;

    SqlSessionFactory dmSessionFactory;

    OracleMapper oracleMapper;

    DmMapper dmMapper;

    private JProgressBar jProgressBar;

    private String table;

    private boolean yb;

    public ConvertTabel(SqlSessionFactory oracleSessionFactory, SqlSessionFactory dmSessionFactory, JProgressBar progressBar, String table, boolean yb) {
        this.oracleSessionFactory = oracleSessionFactory;
        this.dmSessionFactory = dmSessionFactory;
        this.jProgressBar = progressBar;
        this.table = table;
        this.yb = yb;
    }

    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see Thread#run()
     */
    @Override
    public void run() {
        if (yb) {
            ConvertFetchSize();
        } else {
            ConvertMain();
        }
    }


    public ArrayList<String> errors = new ArrayList<>();


    private long all = 0; // 总条数
    private int pages = 0; // 总页数
    private int pageNum = 1;
    private boolean next = true;

    /**
     * 数据迁移
     */
    public void ConvertMain() {
        SqlSession oracleSession = oracleSessionFactory.openSession();
        SqlSession dmSession = dmSessionFactory.openSession();
        oracleMapper = oracleSession.getMapper(OracleMapper.class);
        dmMapper = dmSession.getMapper(DmMapper.class);
        dmMapper.del(table);
        dmSession.commit();
        File file = new File("D://error-" + table + ".txt");
        long counts = oracleMapper.count(table);
        System.out.println(table + " ==>" + counts);
        jProgressBar.setMaximum(Math.toIntExact(counts));
        try {
            while (next) {
                Page<HashMap<String, Object>> page = PageHelper.startPage(pageNum, AppManager.pages).doSelectPage(() -> oracleMapper.query(table, null));
                all = page.getTotal();
                pages = page.getPages();
                List<HashMap<String, Object>> list = page.getResult();
                if (list != null) {
                    // 转换数据格式
                    try {
                        ConvertTabel.convertType(list);
                        dmMapper.install(table, list);
                    } catch (Exception e) {
                        e.printStackTrace();
                        errors.add("ERROR: " + table + " ==> Page:" + pageNum + "  ==>  " + e.getMessage());
                        list.stream().forEach(map -> {
                            StringBuffer msgs = new StringBuffer();
                            map.keySet().forEach(key -> {
                                msgs.append(key + ">" + map.get(key) + " | ");
                            });
                            errors.add(msgs.toString());
                        });
                        try {
                            IOUtils.writeLines(errors, null, new FileOutputStream(file), "GBK");
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    } finally {
                        dmSession.commit();
                    }
                }
                jProgressBar.setValue(pageNum * AppManager.pages);
                jProgressBar.setString("OK  " + table + " => " + (pageNum * AppManager.pages) + "/" + all);
                if (pageNum > pages) {
                    next = false;
                }
                pageNum++;
            }
            jProgressBar.setString("OK  " + table + " => " + all + "/" + all);
            jProgressBar.setValue((int) all);
            jProgressBar.setBackground(Color.GREEN);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            oracleSession.commit();
            dmSession.commit();
        }
    }


    /**
     * 数据迁移 游标处理
     */
    public void ConvertFetchSize() {
        try {
            SqlSession oracleSession = oracleSessionFactory.openSession();
            SqlSession dmSession = dmSessionFactory.openSession();
            oracleMapper = oracleSession.getMapper(OracleMapper.class);
            dmMapper = dmSession.getMapper(DmMapper.class);
            dmMapper.del(table);
            dmSession.commit();
            all = oracleMapper.count(table);
            AtomicInteger index = new AtomicInteger();
            jProgressBar.setMaximum(Math.toIntExact(all));
            oracleMapper.queryFetch(table, resultContext -> {
                index.getAndIncrement();
                HashMap<String, Object> map = resultContext.getResultObject();
                convertType(map);
                try {
                    dmMapper.installOne(table, map);
                } catch (Exception e) {
                    errors.add(map.toString());
                    errors.add("ERROR: " + table + " ==> Page:" + pageNum + "  ==>  " + e.getMessage());
                    throw e;
                } finally {
                    jProgressBar.setValue(index.get());
                    jProgressBar.setString("OK  " + table + " => " + index.get() + "/" + all);
                    dmSession.commit();
                }

            });
            jProgressBar.setValue((int) all);
            jProgressBar.setBackground(Color.GREEN);
            oracleSession.commit();
            dmSession.close();
            oracleSession.close();
        } finally {
            try {
                File file = new File("D://error-" + table + ".txt");
                IOUtils.writeLines(errors, null, new FileOutputStream(file), "GBK");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }


    /**
     * 转换数据类型
     */
    private static void convertType(List<HashMap<String, Object>> list) {
        list.stream().forEach(map -> {
            convertType(map);
        });
    }


    private static void convertType(HashMap<String, Object> map) {
        map.keySet().stream().forEach(key -> {
            Object o = map.get(key);
            String type = o.getClass().getTypeName();
            switch (type) {
                case "java.sql.Timestamp":
                    try {
                        java.sql.Timestamp date = (java.sql.Timestamp) map.get(key);
                        map.put(key, AppManager.format.format(new Date(date.getTime())));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case "oracle.sql.CLOB":
                    String reString = null;
                    oracle.sql.CLOB clob = (oracle.sql.CLOB) map.get(key);
                    if (clob != null) {
                        Reader is = null;// 得到流
                        try {
                            is = clob.getCharacterStream();
                            BufferedReader br = new BufferedReader(is);
                            String s = br.readLine();
                            StringBuffer sb = new StringBuffer();
                            while (s != null) {
                                // 执行循环将字符串全部取出付值给StringBuffer由StringBuffer转成STRING
                                sb.append(s);
                                s = br.readLine();
                            }
                            reString = sb.toString();
                        } catch (SQLException | IOException throwables) {
                            throwables.printStackTrace();
                        }
                    }
                    map.put(key, reString);
                    break;
                case "oracle.sql.BLOB":
                    oracle.sql.BLOB blob = (BLOB) map.get(key);
                    byte[] bytes = blob.getBytes();
                    map.put(key, bytes);
                    break;
            }
        });
    }

}
